﻿using Newtonsoft.Json.Linq;

namespace MicroCloud.Message.Events
{
    #region "消息事件处理器"
    /// <summary>
    /// 消息事件处理器
    /// </summary>
    public class MessageEventHandler : EventHandlerBase<MessageEventData>
    {
        #region "属性"
        #region "获取 服务提供者"
        /// <summary>
        /// 获取 服务提供者
        /// </summary>
        protected IServiceProvider ServiceProvider { get; }
        #endregion
        #region "获取 日志记录器"
        /// <summary>
        /// 获取 日志记录器
        /// </summary>
        protected ILogger Logger => ServiceProvider.GetLogger(GetType());
        #endregion
        #region "获取 通信连接用户缓存"
        /// <summary>
        /// 获取 通信连接用户缓存
        /// </summary>
        protected IConnectionUserCache UserCache => ServiceProvider.GetService<IConnectionUserCache>();
        #endregion

        #region "获取 消息服务"
        /// <summary>
        /// 获取 消息服务
        /// </summary>
        protected IMessageService MessageService => ServiceProvider.GetService<IMessageService>();
        #endregion
        #region "获取 消息接收者仓储模型"
        /// <summary>
        /// 获取 消息接收者仓储模型
        /// </summary>
        protected IRepository<MessageReceiver, long> MessageReceiverRepository => ServiceProvider.GetService<IRepository<MessageReceiver, long>>();
        #endregion

        #endregion

        #region "构造函数"
        #region "初始化一个消息创建事件处理器的新实例"
        /// <summary>
        /// 初始化一个消息创建事件处理器 <see cref="MessageEventHandler"/> 的新实例
        /// </summary>
        /// <param name="provider">服务提供者</param>
        public MessageEventHandler(IServiceProvider provider)
        {
            ServiceProvider = provider;
        }
        #endregion

        #endregion

        #region "方法"
        #region "事件处理"
        /// <summary>
        /// 事件处理
        /// </summary>
        /// <param name="eventData">事件源数据</param>
        /// <param name="provider">服务提供者</param>
        public override void Handle(MessageEventData eventData, IServiceProvider provider)
        {
            var messages = eventData.Messages;
            var dateTimeNow = DateTime.Now;
            foreach (var message in messages)
            {
                switch (eventData.OperateType)
                {
                    case OperateType.Insert:
                    case OperateType.Update:
                        if (!message.IsSent)
                        {
                            var sendTime = message.SendTime;
                            var cronString = CronHelper.GetCronString(sendTime, false);
                            RecurringJob.AddOrUpdate(MessageService.GetMessageSendJobId(message.Id.ToString()), () => MessageService.SendMessages(message.Id), cronString, new RecurringJobOptions { TimeZone = TimeZoneInfo.Local });
                        }
                        else if (message.IsSent && message.StorageDays > 0)
                        {
                            var messageJobId = MessageService.GetMessageDeleteJobId(message.Id.ToString());
                            RecurringJob.RemoveIfExists(messageJobId);
                            //是否立即删除
                            TimeSpan timeSpan = new(message.SendTime.AddDays(message.StorageDays).Ticks - dateTimeNow.Ticks);
                            if (timeSpan.TotalMinutes <= 1)
                            {
                                MessageService.DeleteMessages(message.Id);
                            }
                            else
                            {
                                var deleteTime = message.SendTime.AddDays(message.StorageDays);
                                var cronString = CronHelper.GetCronString(deleteTime, false);
                                RecurringJob.AddOrUpdate(messageJobId, () => MessageService.DeleteMessages(message.Id), cronString, new RecurringJobOptions { TimeZone = TimeZoneInfo.Local });
                            }
                        }
                        break;
                    case OperateType.Delete:
                        var messageReceivers = eventData.MessageReceivers.Where(o => o.MessageId == message.Id).ToList();
                        if (messageReceivers?.Count <= 0)
                        {
                            messageReceivers = message.Receivers.ToList();
                        }
                        if (messageReceivers?.Count > 0)
                        {
                            if (message.IsSent)
                            {
                                var messageDto = message.MapTo<MessageEntity, MessageDto>();
                                var messageMethod = $"{message.Method}_DELETE";
                                foreach (var receiver in messageReceivers)
                                {
                                    var user = UserCache.GetUser(receiver.ReceiverId.ToString()).Result;
                                    if (user?.ConnectionIds.Count > 0)
                                    {
                                        eventData.GetClients(user.ConnectionIds)?.SendAsync(messageMethod, messageDto)?.Wait();
                                        Logger.LogDebug("内部消息 {id} 通过方法 {method} 发送至用户 {receiverId}", message.Id, messageMethod, receiver.ReceiverId);
                                    }
                                }
                            }
                            MessageReceiverRepository.DeleteBatch(o => o.MessageId == message.Id);
                        }
                        RecurringJob.RemoveIfExists(MessageService.GetMessageSendJobId(message.Id.ToString()));
                        RecurringJob.RemoveIfExists(MessageService.GetMessageDeleteJobId(message.Id.ToString()));
                        break;
                }
            }
        }
        #endregion

        #endregion

    }
    #endregion

    #region "模板消息事件处理器"
    /// <summary>
    /// 模板消息事件处理器
    /// </summary>
    public class TemplateMessageEventHandler : EventHandlerBase<TemplateMessageEventData>
    {
        #region "属性"
        #region "获取 服务提供者"
        /// <summary>
        /// 获取 服务提供者
        /// </summary>
        protected IServiceProvider ServiceProvider { get; }
        #endregion
        #region "获取 日志记录器"
        /// <summary>
        /// 获取 日志记录器
        /// </summary>
        protected ILogger Logger => ServiceProvider.GetLogger(GetType());
        #endregion

        #region "获取 消息服务"
        /// <summary>
        /// 获取 消息服务
        /// </summary>
        protected IMessageService MessageService => ServiceProvider.GetService<IMessageService>();
        #endregion

        #endregion

        #region "构造函数"
        #region "初始化一个模板消息创建事件处理器的新实例"
        /// <summary>
        /// 初始化一个模板消息创建事件处理器 <see cref="TemplateMessageEventHandler"/> 的新实例
        /// </summary>
        /// <param name="provider">服务提供者</param>
        public TemplateMessageEventHandler(IServiceProvider provider)
        {
            ServiceProvider = provider;
        }
        #endregion

        #endregion

        #region "方法"
        #region "事件处理"
        /// <summary>
        /// 事件处理
        /// </summary>
        /// <param name="eventData">事件源数据</param>
        /// <param name="provider">服务提供者</param>
        public override void Handle(TemplateMessageEventData eventData, IServiceProvider provider)
        {
            var messages = eventData.TemplateMessages;
            foreach (var message in messages)
            {
                switch (eventData.OperateType)
                {
                    case OperateType.Insert:
                        if (!message.CronExpression.IsMissing() && message.Enabled)
                        {
                            RecurringJob.AddOrUpdate(MessageService.GetMessageTemplateJobId(message.Id.ToString()), () => MessageService.SendTemplateMessages(message.Id), message.CronExpression, new RecurringJobOptions { TimeZone = TimeZoneInfo.Local });
                        }
                        break;
                    case OperateType.Update:
                        if (!message.CronExpression.IsMissing() && message.Enabled)
                        {
                            RecurringJob.AddOrUpdate(MessageService.GetMessageTemplateJobId(message.Id.ToString()), () => MessageService.SendTemplateMessages(message.Id), message.CronExpression, new RecurringJobOptions { TimeZone = TimeZoneInfo.Local });
                        }
                        else
                        {
                            RecurringJob.RemoveIfExists(MessageService.GetMessageTemplateJobId(message.Id.ToString()));
                        }
                        break;
                    case OperateType.Delete:
                        RecurringJob.RemoveIfExists(MessageService.GetMessageTemplateJobId(message.Id.ToString()));
                        break;
                }
            }
        }
        #endregion

        #endregion

    }
    #endregion

    #region "消息发送事件处理器"
    /// <summary>
    /// 消息发送事件处理器
    /// </summary>
    public class MessageSendEventHandler : EventHandlerBase<MessageSendEventData>
    {
        #region "属性"
        #region "获取 服务提供者"
        /// <summary>
        /// 获取 服务提供者
        /// </summary>
        protected IServiceProvider ServiceProvider { get; }
        #endregion
        #region "获取 日志记录器"
        /// <summary>
        /// 获取 日志记录器
        /// </summary>
        protected ILogger Logger => ServiceProvider.GetLogger<MessageSendEventHandler>();
        #endregion
        #region "获取 SignalR服务"
        /// <summary>
        /// 获取 SignalR服务
        /// </summary>
        protected ISignalRService SignalRService => ServiceProvider.GetService<ISignalRService>();
        #endregion
        #region "获取 通信连接用户缓存"
        /// <summary>
        /// 获取 通信连接用户缓存
        /// </summary>
        protected IConnectionUserCache UserCache => ServiceProvider.GetService<IConnectionUserCache>();
        #endregion

        #region "获取 消息服务"
        /// <summary>
        /// 获取 消息服务
        /// </summary>
        protected IMessageService MessageService => ServiceProvider.GetService<IMessageService>();
        #endregion
        #region "获取 Email发送功能"
        /// <summary>
        /// 获取 Email发送功能
        /// </summary>
        protected IEmailSender EmailSender => ServiceProvider.GetRequiredService<IEmailSender>();
        #endregion

        #endregion

        #region "构造函数"
        #region "初始化一个消息发送事件处理器的新实例"
        /// <summary>
        /// 初始化一个消息发送事件处理器 <see cref="MessageSendEventHandler"/> 的新实例
        /// </summary>
        /// <param name="provider">服务提供者</param>
        public MessageSendEventHandler(IServiceProvider provider)
        {
            ServiceProvider = provider;
        }
        #endregion

        #endregion

        #region "方法"
        #region "事件处理"
        /// <summary>
        /// 事件处理
        /// </summary>
        /// <param name="eventData">事件源数据</param>
        /// <param name="provider">服务提供者</param>
        public override void Handle(MessageSendEventData eventData, IServiceProvider provider)
        {
            var messages = eventData.Messages;
            var dateTimeNow = DateTime.Now;
            if (messages?.Count > 0)
            {
                foreach (var message in messages)
                {
                    var messageReceivers = eventData.MessageReceivers.Where(o => o.MessageId == message.Id).ToList();
                    if (messageReceivers?.Count <= 0)
                    {
                        messageReceivers = message.Receivers.ToList();
                    }
                    if (messageReceivers?.Count > 0)
                    {
                        foreach (var messageReceiver in messageReceivers)
                        {
                            var messageReceiverDto = messageReceiver.MapTo<MessageReceiver, MessageReceiverOutputDto>();
                            var messageDto = message.MapTo<MessageEntity, MessageDto>();
                            messageDto.LastReadTime = null;
                            messageDto.LastReadWay = null;
                            foreach (var sendWays in messageReceiverDto.SendWays)
                            {
                                switch (sendWays)
                                {
                                    case MessageSendWay.Internal:
                                        var user = UserCache.GetUser(messageReceiverDto.ReceiverId.ToString()).Result;
                                        if (user?.ConnectionIds.Count > 0)
                                        {
                                            eventData.GetClients(user.ConnectionIds)?.SendAsync(message.Method, messageDto)?.Wait();
                                            Logger.LogDebug("内部消息 {id} 通过方法 {method} 发送至用户 {receiverId}", message.Id, message.Method, messageReceiverDto.ReceiverId);
                                        }
                                        break;
                                    case MessageSendWay.Email:
                                        var receiver = eventData.MessageReceiverUsers.FirstOrDefault(o => o.Id == messageReceiver.ReceiverId);
                                        if (!receiver.EmailConfirmed)
                                        {
                                            Logger.LogWarning("邮件消息 {id} 由于用户 {receiverId} 邮箱未设置或未确认，将跳过该用户邮箱发送。", message.Id, messageReceiverDto.ReceiverId);
                                            continue;
                                        }
                                        string receiverEmail = receiver.Email;
                                        if (receiverEmail.IsMissing())
                                        {
                                            Logger.LogWarning("邮件消息 {id} 由于用户 {receiverId} 邮箱为空，将跳过该用户邮箱发送。", message.Id, messageReceiverDto.ReceiverId);
                                            continue;
                                        }
                                        EmailSendDto emailSendDto = new()
                                        {
                                            Subject = messageDto.Title,
                                            Body = $"{messageDto.Content}",
                                            BodyFormat = EmailBodyFormat.Html,
                                            ToEmails = new string[] { receiverEmail },
                                        };
                                        var messageMethod = message.Method.ToUpper();
                                        switch (messageMethod)
                                        {
                                            case "MSG_QUERY":
                                                HandleQueryMessageEmailBody(emailSendDto, messageDto);
                                                break;
                                            case "MSG_NOTICE":
                                                HandleNoticeMessageEmailBody(emailSendDto, messageDto);
                                                break;
                                        }
                                        EmailSender.SendEmailAsync(emailSendDto);
                                        Logger.LogDebug("邮件消息 {id} 通过邮箱 {receiverEmail} 发送至用户 {receiverId}", message.Id, receiverEmail, messageReceiverDto.ReceiverId);
                                        break;
                                    case MessageSendWay.OAuth2:
                                        break;
                                }
                            }
                        }
                    }

                    if (message.IsSent && message.StorageDays > 0)
                    {
                        var messageJobId = MessageService.GetMessageDeleteJobId(message.Id.ToString());
                        RecurringJob.RemoveIfExists(messageJobId);
                        //是否立即删除
                        TimeSpan timeSpan = new(message.SendTime.AddDays(message.StorageDays).Ticks - dateTimeNow.Ticks);
                        if (timeSpan.TotalMinutes <= 1)
                        {
                            MessageService.DeleteMessages(message.Id);
                        }
                        else
                        {
                            var deleteTime = message.SendTime.AddDays(message.StorageDays);
                            var cronString = CronHelper.GetCronString(deleteTime, false);
                            RecurringJob.AddOrUpdate(messageJobId, () => MessageService.DeleteMessages(message.Id), cronString, new RecurringJobOptions { TimeZone = TimeZoneInfo.Local });
                        }
                    }
                }
            }
        }
        #endregion

        #endregion

        #region "受保护的方法"
        #region "处理查询消息邮件体"
        /// <summary>
        /// 处理查询消息邮件体
        /// </summary>
        /// <param name="emailSendDto"></param>
        /// <param name="messageDto"></param>
        /// <returns></returns>
        protected virtual EmailSendDto HandleQueryMessageEmailBody(EmailSendDto emailSendDto, MessageDto messageDto)
        {
            var containData = true;
            if (messageDto.MessageType == MessageType.Image || messageDto.MessageType == MessageType.File || messageDto.MessageType == MessageType.News)
            {
                string fileName = messageDto.Payload.FileName;
                string fileBase64 = $"{messageDto.Payload.FileBase64Header}{messageDto.Payload.FileBase64String}";
                emailSendDto.Attachments = new EmailAttachmentDto[]
                {
                    new EmailAttachmentDto {  FileName = fileName, FileBase64 = fileBase64 }
                };
                switch (messageDto.MessageType)
                {
                    case MessageType.Image:
                        emailSendDto.Body = @$"{emailSendDto.Body} <br />
<center><img src=""{fileBase64}""></center>";
                        containData = false;
                        break;
                }
            }
            if (messageDto.Payload.Data != null)
            {
                var payloadDataType = messageDto.Payload.Data.GetType();
                DataSet payloadData = null;
                if (typeof(JObject) == payloadDataType)
                {
                    payloadData = ((JObject)messageDto.Payload.Data).ToString().ToModel<DataSet>();
                }
                else if (typeof(string) == payloadDataType)
                {
                    payloadData = ((string)messageDto.Payload.Data).ToModel<DataSet>();
                }
                else if (typeof(DataSet) == payloadDataType)
                {
                    payloadData = ((DataSet)messageDto.Payload.Data);
                }
                //处理DataSet转Excel附件
                if (payloadData != null)
                {
                    //var xlsxWorkbook = new XSSFWorkbook();  // 创建Excel2007-2021及以后格式的工作簿
                    //foreach (DataTable dt in payloadData.Tables)
                    //{
                    //    var workbook = xlsxWorkbook;
                    //    if (workbook == null) { return; }
                    //    if (dt?.Rows?.Count <= 0) { return; }
                    //    var sheetName = dt.TableName.IsMissing() ? $"Sheet{workbook.NumberOfSheets + 1}" : dt.TableName;
                    //    var sheet = workbook.CreateSheet(sheetName);   // 在工作簿中创建工作表
                    //    int rowCount = dt.Rows.Count;//行数
                    //    int columnCount = dt.Columns.Count;//列数
                    //                                       //设置列头
                    //    var row = sheet.CreateRow(0);//excel第一行设为列头
                    //    ICell cell;
                    //    for (int c = 0; c < columnCount; c++)
                    //    {
                    //        cell = row.CreateCell(c);
                    //        cell.SetCellValue(dt.Columns[c].ColumnName);
                    //    }
                    //    //设置每行每列的单元格,
                    //    for (int i = 0; i < rowCount; i++)
                    //    {
                    //        row = sheet.CreateRow(i + 1);
                    //        for (int j = 0; j < columnCount; j++)
                    //        {
                    //            cell = row.CreateCell(j);//excel第二行开始写入数据
                    //            cell.SetCellValue(dt.Rows[i][j].ToString());
                    //        }
                    //    }
                    //}
                    //var excelStream = new MemoryStream();
                    //xlsxWorkbook.Write(excelStream);
                    //var excelBase64String = excelStream.ToBase64String();
                    var excelBase64String = payloadData.ToExcelBase64String();
                    if (!excelBase64String.IsMissing())
                    {
                        var attachments = emailSendDto.Attachments.ToList();
                        attachments.Add(new EmailAttachmentDto { FileName = "Data.xlsx", FileBase64 = excelBase64String });
                        emailSendDto.Attachments = attachments.ToArray();
                    }
                }
                //处理在邮件内容中展示Table表
                var dataHtml = "";
                if (containData)
                {
                    dataHtml = payloadData?.ToHtmlString();
                }
                if (!dataHtml.IsMissing())
                {
                    emailSendDto.Body = @$"{emailSendDto.Body} <br />
{dataHtml}";
                }
            }
            return emailSendDto;
        }
        #endregion
        #region "处理公告消息邮件体"
        /// <summary>
        /// 处理公告消息邮件体
        /// </summary>
        /// <param name="emailSendDto"></param>
        /// <param name="messageDto"></param>
        /// <returns></returns>
        protected virtual EmailSendDto HandleNoticeMessageEmailBody(EmailSendDto emailSendDto, MessageDto messageDto)
        {
            if (messageDto.Payload != null)
            {
                var content = messageDto.Payload.Content;
                if (content != null)
                {
                    emailSendDto.Body = @$"{emailSendDto.Body} <br />
{content}";
                }
                var files = messageDto.Payload.Files;
                if (files != null)
                {
                    var attachments = emailSendDto.Attachments.ToList();
                    foreach (var file in files)
                    {
                        if (file?.FileName != null && file?.FileBase64 != null)
                        {
                            attachments.Add(new EmailAttachmentDto { FileName = file.FileName, FileBase64 = file.FileBase64 });
                        }
                    }
                    emailSendDto.Attachments = attachments.ToArray();
                }
            }
            return emailSendDto;
        }
        #endregion

        #endregion

    }
    #endregion

    #region "消息读取事件处理器"
    /// <summary>
    /// 消息读取事件处理器
    /// </summary>
    public class MessageReadEventHandler : EventHandlerBase<MessageReadEventData>
    {
        #region "属性"
        #region "获取 服务提供者"
        /// <summary>
        /// 获取 服务提供者
        /// </summary>
        protected IServiceProvider ServiceProvider { get; }
        #endregion
        #region "获取 日志记录器"
        /// <summary>
        /// 获取 日志记录器
        /// </summary>
        protected ILogger Logger => ServiceProvider.GetLogger<MessageReadEventHandler>();
        #endregion
        #region "获取 SignalR服务"
        /// <summary>
        /// 获取 SignalR服务
        /// </summary>
        protected ISignalRService SignalRService => ServiceProvider.GetService<ISignalRService>();
        #endregion
        #region "获取 通信连接用户缓存"
        /// <summary>
        /// 获取 通信连接用户缓存
        /// </summary>
        protected IConnectionUserCache UserCache => ServiceProvider.GetService<IConnectionUserCache>();
        #endregion

        #region "获取 消息服务"
        /// <summary>
        /// 获取 消息服务
        /// </summary>
        protected IMessageService MessageService => ServiceProvider.GetService<IMessageService>();
        #endregion
        #region "获取 Email发送功能"
        /// <summary>
        /// 获取 Email发送功能
        /// </summary>
        protected IEmailSender EmailSender => ServiceProvider.GetRequiredService<IEmailSender>();
        #endregion

        #endregion

        #region "构造函数"
        #region "初始化一个消息读取事件处理器的新实例"
        /// <summary>
        /// 初始化一个消息读取事件处理器 <see cref="MessageReadEventHandler"/> 的新实例
        /// </summary>
        /// <param name="provider">服务提供者</param>
        public MessageReadEventHandler(IServiceProvider provider)
        {
            ServiceProvider = provider;
        }
        #endregion

        #endregion

        #region "方法"
        #region "事件处理"
        /// <summary>
        /// 事件处理
        /// </summary>
        /// <param name="eventData">事件源数据</param>
        /// <param name="provider">服务提供者</param>
        public override void Handle(MessageReadEventData eventData, IServiceProvider provider)
        {
            var messages = eventData.Messages;
            var dateTimeNow = DateTime.Now;
            if (messages?.Count > 0)
            {
                foreach (var message in messages)
                {
                    var messageReceivers = eventData.MessageReceivers.Where(o => o.MessageId == message.Id).ToList();
                    if (messageReceivers?.Count <= 0)
                    {
                        messageReceivers = message.Receivers.ToList();
                    }
                    if (messageReceivers?.Count > 0)
                    {
                        if (message.IsSent)
                        {
                            foreach (var messageReceiver in messageReceivers)
                            {
                                var read = messageReceiver.LastReadTime.HasValue ? "READ" : "UNREAD";
                                var messageDto = message.MapTo<MessageEntity, MessageDto>();
                                var messageMethod = $"{message.Method}_{read}";

                                var user = UserCache.GetUser(messageReceiver.ReceiverId.ToString()).Result;
                                if (user?.ConnectionIds.Count > 0)
                                {
                                    eventData.GetClients(user.ConnectionIds)?.SendAsync(messageMethod, messageDto)?.Wait();
                                    Logger.LogDebug("内部消息 {id} 通过方法 {method} 发送至用户 {receiverId}", message.Id, messageMethod, messageReceiver.ReceiverId);
                                }
                            }
                        }
                    }
                }
            }
        }
        #endregion

        #endregion

    }
    #endregion

}
